from datetime import datetime, timedelta

from django.db import models


# Create your models here.

class Member(models.Model):
    name = models.CharField('姓名', max_length=100)
    SNO = models.CharField('学号', max_length=100, unique=True)
    OpenID = models.CharField('微信Id', max_length=100)
    category = models.IntegerField()
    addition = models.CharField('备注', max_length=1000)
    sex = models.CharField('性别', max_length=2)
    phone = models.CharField('手机', max_length=20, default='')
    major = models.CharField('班级', max_length=20, default='')
    college = models.CharField('学院', max_length=20, default='')
    stat = models.CharField("擅长", max_length=10)
    good = models.IntegerField()

    def __str__(self):
        return self.name


def mem_rule_analyse(mem_rule):
    res = {}
    for rule in mem_rule.split(';'):
        r = rule.split(' ')
        res[r[0]] = int(r[1])
    return res


def str_mem_rule(mem_rule):
    if mem_rule == '全员':
        return '全员'
    r = mem_rule_analyse(mem_rule)
    res = ''
    if r['组数']>9:
        res+= str(r["组人"])+"人一组/"
    else:
        for i in range(r['组数']):
            res += str(r['组人']) + '人/'
    return res[:-1]


'''
def balance_mem_rule(mem_rule, members, trans=0):
    # TODO ：修改平衡规则
    if len(members) < sum(mem_rule.values()):  # 所有人都可以参加
        for k in mem_rule:
            num_x = len([m for m in members if m.user.sex == k])
            mem_rule[k] = num_x
        return mem_rule
    for k in mem_rule:  # 必须筛选掉些人
        num_x = len([m for m in members if m.user.sex == k])
        if num_x < mem_rule[k]:  # 检查是否满足
            trans = mem_rule[k] - num_x
            mem_rule[k] = num_x
            return balance_mem_rule(mem_rule, members, trans)
        elif trans:  # 检查是否存有余量
            if mem_rule[k] + trans < num_x:  # 该性别报名在规则内允许可以存下余量
                mem_rule[k] += trans
                return mem_rule
    return mem_rule
'''


def cross_sort(members):
    # 交叉排序分组
    members.sort(key=lambda x: (-x.user.category))
    g1 = [m for m in members if m.user.good == 1]
    g2 = [m for m in members if m.user.good == 2]
    g3 = [m for m in members if m.user.good == 3]
    turn = 0
    for i in range(len(members)):
        if turn == 0 and len(g1):
            yield g1.pop(0)
        elif turn == 1 and len(g2):
            yield g2.pop(0)
        elif turn == 2 and len(g3):
            yield g3.pop(0)
        turn = (turn + 1) % 3


class Activity(models.Model):
    name = models.CharField('名称', max_length=1000)
    start_time = models.DateTimeField()  # 可设置时间
    end_time = models.DateTimeField()
    sustained = models.CharField('持续时间', max_length=100, null=True)
    member_rule = models.CharField('报名对象规则', max_length=20)
    # 组人{n} 一组内包含的人数 ；组数{n} 分组数量；组长 有无组长； '分号'分割';' '分割数字
    repeat_rule = models.CharField('活动重复规则', max_length=20)  # W{n}定时周几;
    create_time = models.DateField(auto_now=True)
    introduce = models.CharField('简介', max_length=10000)
    founder = models.ForeignKey(Member)
    location = models.CharField('地点', max_length=1000)
    available = models.BooleanField('有效性', default=True)
    finish_fresh = models.BooleanField('是否刷新', default=False)

    @staticmethod
    def str_mem(mem_list):
        return ' \n '.join(map(str, mem_list))

    def regist_start(self):
        return self.start_time - timedelta(days=5)

    def regist_end(self):
        return self.start_time - timedelta(days=1)

    def str_activity_time(self):
        # 转换活动时间
        if not self.sustained:
            return "时间: {} 到 {}".format(self.str_time(self.start_time), self.str_time(self.end_time))
        else:
            return "时间: " + self.sustained

    @staticmethod
    def str_time(date):
        weeks = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
        w = weeks[int(datetime.strftime(date, '%w'))]
        h = int(datetime.strftime(date, '%H'))
        m = datetime.strftime(date, '%M')
        if h < 12:
            h = "上午{}点{}分".format(h, m)
        else:
            h = "下午{}点{}分".format(h - 12, m)
        return w + h

    @staticmethod
    def get_now_activity():
        for activity in Activity.objects.filter(available=True):
            activity.fresh()
            if activity.regist_start().replace(tzinfo=None) < datetime.now() < activity.start_time.replace(
                    tzinfo=None):
                yield activity

    def unregist(self, member):
        if datetime.now() > self.regist_end().replace(tzinfo=None):
            return "活动报名结束，请联系管理员说明不参与理由"
        else:
            attend = Attend.objects.filter(available=True).filter(user=member).filter(activity=self).first()
            if not attend:
                return "尚未报名"
            attend.delete()
            return "成功取消报名 {}".format(self.name)

    def fresh(self):
        """更新活动时间和筛选人员"""
        # 判断是否需要确定人员：
        if self.regist_end().replace(tzinfo=None) < datetime.now() and not self.finish_fresh:
            # 删除所有已有分组
            for g in self.groups.all():
                for m in g.members.all():
                    m.group = None
                    m.save()
                g.delete()

            # 获取所有的报名对象
            members = list(self.now_enroll())
            # 根据人员组成规则开始筛选
            mem_rule = mem_rule_analyse(self.member_rule)
            cs_member = list(cross_sort(members))
            if len(cs_member):
                for j in range(mem_rule['组数']):  # 分组
                    new_group = Group()
                    new_group.activity = self
                    new_group.save()
                    for g in range(mem_rule['组人']):
                        if len(cs_member):
                            t = cs_member.pop(0)  # 弹出一人
                        else:
                            break
                        if g == 0 and '组长' in mem_rule:
                            t.is_leader = True  # 设置为组长
                        t.group = new_group
                        t.save()
                    else:
                        break
            # 剩余人报名失败
            for m in cs_member:
                m.available = False
                m.save()
            self.finish_fresh = True  # 完成刷新

        # 判断是否要更新开始时间和结束时间
        if self.start_time.replace(tzinfo=None) < datetime.now():
            # 取消所有的参与者的available
            for attend in self.now_enroll():
                attend.available = False
                attend.save()
            # 需要更新,检查更新周期
            if self.repeat_rule == 'W':
                self.start_time += timedelta(days=7)
                self.end_time += timedelta(days=7)
                self.save()
            self.finish_fresh = False
        self.save()

    def attend(self, member):
        """添加一个参加人员"""
        if self.regist_end().replace(tzinfo=None) < datetime.now():
            return "报名时间结束"

        if Attend.objects.filter(available=True).filter(user=member).filter(activity=self).first():
            return "{} 已报名 {}".format(member.name, self.name)
        attend = Attend(user=member, activity=self, available=True)
        attend.save()  # 报名完成
        return "{} 成功报名 {}\n\n {t} 前可取消报名 \n\n 回复【我的活动】查询报名情况".format(
            member.name, self.name, t=self.str_time(self.regist_end()), rt=self.str_time(self.start_time))

    def now_enroll(self):
        # 返回当前报名
        return Attend.objects.filter(activity=self).filter(available=True)

    def __str__(self):
        res = " 名称：{} \n\n 简介：\n{} \n\n 地点:{} \n\n {} \n\n 报名人数：{} ".format(
            self.name, self.introduce.replace('\\n', '\n'), self.location, self.str_activity_time(),
            str_mem_rule(self.member_rule))
        return res


class Group(models.Model):
    activity = models.ForeignKey(Activity, related_name='groups')


class Attend(models.Model):
    activity = models.ForeignKey(Activity)
    user = models.ForeignKey(Member)
    is_leader = models.BooleanField(default=False)
    create_time = models.DateField(auto_now=True)
    available = models.BooleanField()  # 是否有效
    group = models.ForeignKey(Group, null=True, related_name='members')

    def affirm(self):
        if self.activity.regist_end().replace(tzinfo=None) < datetime.now():  # 过了报名的最后时间
            return self.available

    def __str__(self):
        return "{}({}){}".format(self.user.name, self.user.sex, "[组长]" if self.is_leader else "")


class Advice(models.Model):
    user = models.ForeignKey(Member)
    content = models.CharField(max_length=3000)
    create_time = models.DateTimeField(auto_now=True)

    @staticmethod
    def get_recent():
        for advice in Advice.objects.all():
            if advice.create_time.replace(tzinfo=None) > datetime.now() - timedelta(days=7):
                yield advice

    def __str__(self):
        return "{}:{}".format(self.user, self.content)
